package cn.xd.base.application.service.query.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.xd.base.application.assembler.*;
import cn.xd.base.application.dto.query.AdminUserQuery;
import cn.xd.base.application.service.query.AdminUserQueryAppService;
import cn.xd.base.basic.type.AdminOrgId;
import cn.xd.base.basic.type.AdminRoleId;
import cn.xd.base.basic.type.AdminUserId;
import cn.xd.base.domain.bean.response.*;
import cn.xd.base.domain.entity.AdminOrg;
import cn.xd.base.domain.entity.AdminRole;
import cn.xd.base.domain.entity.AdminUser;
import cn.xd.base.domain.entity.AdminUserOrgRole;
import cn.xd.base.domain.repository.AdminUserRepository;
import cn.xd.base.persistence.dos.*;
import cn.xd.base.persistence.mps.*;
import cn.xd.common.enums.common.CommonStatusEnum;
import cn.xd.core.response.ObjectResult;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
public class AdminUserQueryAppServiceImpl implements AdminUserQueryAppService {
    @Resource
    private AdminUserMpService adminUserMpService;
    @Resource
    private AdminUserRepository adminUserRepository;
    @Resource
    private AdminRoleMpService adminRoleMpService;
    @Resource
    private AdminOrgMpService adminOrgMpService;
    @Resource
    private AdminOrgRoleMpService adminOrgRoleMpService;
    @Resource
    private AdminUserOrgRoleMpService adminUserOrgRoleMpService;
    @Resource
    private AdminRoleMenuMpService adminRoleMenuMpService;
    @Resource
    private AdminMenuMpService adminMenuMpService;
    @Resource
    private GlobalAppUserMpService globalAppUserMpService;

    @Override
    public List<Long> getRoleIds(Long userId, List<Long> orgIds) {
        List<AdminUserOrgRoleDO> adminUserOrgRoles = (List<AdminUserOrgRoleDO>) adminUserOrgRoleMpService.getAdminUserOrgRoles(userId).get();
        List<Long> adminOrgRoleIds = adminUserOrgRoles.stream().map(AdminUserOrgRoleDO::getOrgRoleId).toList();
        List<Long> roleIds = adminOrgRoleMpService.lambdaQuery()
                .in(AdminOrgRoleDO::getId, adminOrgRoleIds).in(AdminOrgRoleDO::getOrgId, orgIds).list()
                .stream().map(AdminOrgRoleDO::getRoleId).toList();
        return roleIds.stream().filter(item -> {
            AdminRoleDO adminRoleDO = adminRoleMpService.getResult(item).get();
            if (ObjUtil.isEmpty(adminRoleDO) || !adminRoleDO.getStatus().equals(CommonStatusEnum.ENABLE.getCode())) {
                return Boolean.FALSE;
            } else {
                return Boolean.TRUE;
            }
        }).toList();
    }

    public List<Long> getUserIdsByOrgIds(List<Long> orgIds) {
        if (CollUtil.isEmpty(orgIds)) {
            return new ArrayList<>();
        }
        List<Long> orgRoleIds = adminOrgRoleMpService.lambdaQuery().in(AdminOrgRoleDO::getOrgId, orgIds).list()
                .stream().map(AdminOrgRoleDO::getId).toList();
        if (CollUtil.isEmpty(orgRoleIds)) {
            return new ArrayList<>();
        }
        return adminUserOrgRoleMpService.lambdaQuery().in(AdminUserOrgRoleDO::getOrgRoleId, orgRoleIds).list()
                .stream().map(AdminUserOrgRoleDO::getUserId).toList();
    }

    @Override
    public Page<AdminUserDTO> getPage(AdminUserQuery query, List<Long> orgIds) {
        List<Long> userIds = getUserIdsByOrgIds(orgIds);
        if (CollUtil.isEmpty(userIds)) {
            return new Page<>();
        }
        List<Long> userIdsParams = new ArrayList<>();
        if (CollUtil.isNotEmpty(query.getOrgIds())) {
            userIdsParams = getUserIdsByOrgIds(query.getOrgIds());
            if (CollUtil.isEmpty(userIdsParams)) {
                return new Page<>();
            }
        }
        return adminUserMpService.getPage(Wrappers.lambdaQuery(AdminUserDO.class)
                        .like(StrUtil.isNotBlank(query.getName()), AdminUserDO::getName, query.getName())
                        .like(StrUtil.isNotBlank(query.getAccount()), AdminUserDO::getAccount, query.getAccount())
                        .eq(ObjUtil.isNotNull(query.getStatus()), AdminUserDO::getStatus, query.getStatus())
                        .ne(AdminUserDO::getStatus, CommonStatusEnum.DELETED.getCode())
                        .in(AdminUserDO::getId, userIds)
                        .in(CollUtil.isNotEmpty(query.getOrgIds()), AdminUserDO::getId, userIdsParams)
                        .ne(AdminUserDO::getStatus, CommonStatusEnum.DELETED.getCode())
                        .isNull(ObjUtil.isNotEmpty(query.getHasGlobalUserId())&&query.getHasGlobalUserId(),AdminUserDO::getGlobalUserId)
                        .isNotNull(ObjUtil.isNotEmpty(query.getHasGlobalUserId())&&!query.getHasGlobalUserId(),AdminUserDO::getGlobalUserId)
                        .orderByDesc(AdminUserDO::getId)
                , AdminUserAssembler.INSTANCE, query);
    }

    @Override
    public List<AdminUserDTO> getList(AdminUserQuery query, List<Long> orgIds) {
        List<Long> userIds = getUserIdsByOrgIds(orgIds);
        if (CollUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        List<Long> userIdsParams = new ArrayList<>();
        if (CollUtil.isNotEmpty(query.getOrgIds())) {
            userIdsParams = getUserIdsByOrgIds(query.getOrgIds());
            if (CollUtil.isEmpty(userIdsParams)) {
                return new ArrayList<>();
            }
        }
        List<AdminUserDO> list = adminUserMpService.lambdaQuery().like(StrUtil.isNotBlank(query.getName()), AdminUserDO::getName, query.getName())
                .like(StrUtil.isNotBlank(query.getAccount()), AdminUserDO::getAccount, query.getAccount())
                .eq(ObjUtil.isNotNull(query.getStatus()), AdminUserDO::getStatus, query.getStatus())
                .ne(AdminUserDO::getStatus, CommonStatusEnum.DELETED.getCode())
                .in(AdminUserDO::getId, userIds)
                .in(CollUtil.isNotEmpty(query.getOrgIds()), AdminUserDO::getId, userIdsParams)
                .isNull(ObjUtil.isNotEmpty(query.getHasGlobalUserId())&&query.getHasGlobalUserId(),AdminUserDO::getGlobalUserId)
                .isNotNull(ObjUtil.isNotEmpty(query.getHasGlobalUserId())&&!query.getHasGlobalUserId(),AdminUserDO::getGlobalUserId)
                .orderByDesc(AdminUserDO::getId).list();
        return AdminUserAssembler.INSTANCE.fromData(list);
    }

    @Override
    public List<Long> getOrgIdsByAdminUserId(Long userId) {
        if (ObjUtil.isEmpty(userId)) {
            return new ArrayList<>();
        }
        return getOrgRolesByAdminUserId(userId).stream().map(AdminOrgRoleDTO::getOrg).map(AdminOrgDTO::getId).toList();
    }

    @Override
    public List<AdminOrgDTO> getOrgsByAdminUserId(Long userId) {
        List<Long> orgIds = getOrgIdsByAdminUserId(userId);
        if (CollUtil.isEmpty(orgIds)) {
            return new ArrayList<>();
        }
        List<AdminOrgDO> list = adminOrgMpService.lambdaQuery().in(AdminOrgDO::getId, orgIds).orderByDesc(AdminOrgDO::getOrderNum).list();
        return AdminOrgAssembler.INSTANCE.fromData(list);
    }

    @Override
    public List<AdminOrgDTO> getOrgByAccount(String account) {
        AdminUser adminUser = getAdminUserByAccount(account, null);
        if (adminUser == null || adminUser.getId() == null) {
            return new ArrayList<>();
        }
        List<Long> orgIds = getOrgIdsByAdminUserId(adminUser.getId().getValue());
        if (orgIds.isEmpty()) {
            return new ArrayList<>();
        }
        List<AdminOrgDO> list = adminOrgMpService.lambdaQuery().in(AdminOrgDO::getId, orgIds).orderByDesc(AdminOrgDO::getOrderNum).list();
        return AdminOrgAssembler.INSTANCE.fromData(list);
    }

    @Override
    public Boolean checkHasAccount(String account, Long id) {
        return ObjUtil.isNotEmpty(adminUserMpService.getAdminUserByAccount(account, id).get());
    }

    @Override
    public Boolean checkHasGlobalUser(Long globalUserId, Long id) {
        return ObjUtil.isNotEmpty(adminUserMpService.getAdminUserByGlobalUserId(globalUserId, id).get());
    }

    @Override
    public Long getAdminUserIdByGlobalUserId(Long globalUserId) {
        AdminUserDO adminUserDO = adminUserMpService.getAdminUserByGlobalUserId(globalUserId, null).get();
        return ObjUtil.isEmpty(adminUserDO) ? null : adminUserDO.getId();
    }


    private List<AdminOrgRoleDTO> getOrgRolesByAdminUserId(Long userId) {
        AdminUser adminUser = adminUserRepository.find(AdminUserId.of(userId)).isEmptyThrow("未找到该用户:" + userId);
        return getAdminOrgRoleDTOS(adminUser.getOrgRoles());
    }

    /**
     * 通过adminUserOrgRole查询orgRole
     *
     * @param adminUserOrgRoles
     * @return
     */
    private List<AdminOrgRoleDTO> getAdminOrgRoleDTOS(List<AdminUserOrgRole> adminUserOrgRoles) {
        List<AdminOrgRoleDTO> adminOrgRoleDTOS = new ArrayList<>();
        for (AdminUserOrgRole adminUserOrgRole : adminUserOrgRoles) {
            AdminOrgRoleDO adminOrgRoleDO = adminOrgRoleMpService.getResult(adminUserOrgRole.getOrgRoleId()).get();
            if (ObjUtil.isEmpty(adminOrgRoleDO)) {
                continue;
            }
            AdminRole adminRole = adminRoleMpService.getResult(AdminRoleId.of(adminOrgRoleDO.getRoleId()), AdminRoleConverter.INSTANCE).get();
            AdminOrg adminOrg = adminOrgMpService.getResult(AdminOrgId.of(adminOrgRoleDO.getOrgId()), AdminOrgConverter.INSTANCE).get();
            if (!adminRole.getStatus().getValue().equals(CommonStatusEnum.ENABLE.getCode()) || !adminOrg.getStatus().getValue().equals(CommonStatusEnum.ENABLE.getCode())) {
                continue;
            }
            AdminOrgRoleDTO dto = new AdminOrgRoleDTO();
            dto.setId(adminOrgRoleDO.getId());
            dto.setRole(AdminRoleAssembler.INSTANCE.toDTO(adminRole));
            dto.setOrg(AdminOrgAssembler.INSTANCE.toDTO(adminOrg));
            adminOrgRoleDTOS.add(dto);
        }
        return adminOrgRoleDTOS;
    }

    @Override
    public AdminUserDetailDTO getInfo(Long id) {
        AdminUser adminUser = adminUserRepository.find(AdminUserId.of(id)).isEmptyThrow("未找到该用户:" + id);
        AdminUserDetailDTO info = AdminUserDetailAssembler.INSTANCE.toDTO(adminUser);
        if (ObjUtil.isNotEmpty(info.getGlobalUserId())) {
            GlobalAppUserDO globalAppUserDO = globalAppUserMpService.getResult(info.getGlobalUserId())
                    .isEmptyThrow("未找到对应appUser：" + info.getGlobalUserId());
            info.setNickName(globalAppUserDO.getNickName());
            info.setPhone(globalAppUserDO.getPhone());
        }
        List<AdminOrgRoleDTO> adminOrgRoleDTOS = getAdminOrgRoleDTOS(adminUser.getOrgRoles());
        info.setOrgRoles(adminOrgRoleDTOS);
        return info;
    }

    @Override
    public ObjectResult<AdminUserForLoginDTO> getInfoByAccount(String account, Long org) {
        AdminUser adminUser = getAdminUserByAccount(account, null);
        if (adminUser == null) return ObjectResult.of(null);
        return ObjectResult.of(getAdminUserInfoDTO(adminUser, org));
    }

    private AdminUser getAdminUserByAccount(String account, Long id) {
        AdminUserDO adminUserDO = adminUserMpService.getAdminUserByAccount(account, id).get();
        if (ObjUtil.isNull(adminUserDO)) {
            return null;
        }
        return adminUserRepository.find(AdminUserId.of(adminUserDO.getId())).get();
    }

    /**
     * 获取用户详细信息
     *
     * @param adminUser
     * @return
     */
    private AdminUserForLoginDTO getAdminUserInfoDTO(AdminUser adminUser, Long org) {
        AdminUserForLoginDTO info = AdminUserForLoginAssembler.INSTANCE.toDTO(adminUser);

        //数据权限按照最低角色权限
        Integer dataScope = 0;
        List<Long> roles = new ArrayList<>();
        for (AdminUserOrgRole adminUserOrgRole : adminUser.getOrgRoles()) {
            AdminOrgRoleDO adminOrgRoleDO = adminOrgRoleMpService.getResult(adminUserOrgRole.getOrgRoleId()).get();
            if (ObjUtil.isEmpty(adminOrgRoleDO) || ObjUtil.notEqual(adminOrgRoleDO.getOrgId(), org)) {
                continue;
            }
            AdminRoleDO adminRoleDO = adminRoleMpService.getById(adminOrgRoleDO.getRoleId());
            if (ObjUtil.isEmpty(adminRoleDO) || !adminRoleDO.getStatus().equals(CommonStatusEnum.ENABLE.getCode())) {
                continue;
            }
            roles.add(adminRoleDO.getId());
            dataScope = adminRoleDO.getDataScope() > dataScope ? adminRoleDO.getDataScope() : dataScope;
        }
        //权限标识
        Set<String> perms = new HashSet<>();
        if (CollUtil.isNotEmpty(roles)) {
            List<AdminRoleMenuDO> adminRoleMenuDOS = adminRoleMenuMpService.lambdaQuery().in(AdminRoleMenuDO::getRoleId, roles).list();
            for (AdminRoleMenuDO adminRoleMenuDO : adminRoleMenuDOS) {
                AdminMenuDO adminMenuDO = adminMenuMpService.getById(adminRoleMenuDO.getMenuId());
                perms.add(adminMenuDO.getPerms());
            }
        }

        info.setDataScope(dataScope);
        info.setRoleIds(roles);
        info.setPerms(perms);
        return info;
    }
}
